/*******************************************************************************
 * Copyright (c) 2000, 2004 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Common Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/cpl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
module dwt.ole.win32.olepropertychangesink;


private import dwt.dwt;



private import dwt.ole.win32.ole;
private import dwt.ole.win32.olecontrolsite;
private import dwt.ole.win32.olemisc;
private import dwt.internal.ole.win32.com;
private import dwt.internal.ole.win32.ifs;
private import dwt.internal.ole.win32.extras;




private class _IPropertyNotifySinkImpl : IPropertyNotifySink {

	private import std.c.windows.windows;
	private import std.c.windows.com;


	OlePropertyChangeSink	parent;
	this(OlePropertyChangeSink	p) { parent = p; }
extern (Windows):
	// interface of IUnknown
	HRESULT QueryInterface(REFIID riid, void ** ppvObject) { return parent.QueryInterface(riid, ppvObject); }
	ULONG AddRef()	{ return parent.AddRef(); }
	ULONG Release()	{ return parent.Release(); }

	// interface of IPropertyNotifySink
	int OnChanged(int dispID) { return parent.OnChanged(dispID); }
	int OnRequestEdit(int dispID) { return parent.OnRequestEdit(dispID); }
}


class OlePropertyChangeSink {

	private import std.c.windows.windows;
	private import std.c.windows.com;


	private OleControlSite controlSite;
	//private IUnknown objIUnknown;

	private _IPropertyNotifySinkImpl iPropertyNotifySink;

	private int refCount;

	private int propertyCookie;

	private OleEventTable eventTable;

this(OleControlSite controlSite) {

	this.controlSite = controlSite;

	createCOMInterfaces();
}

HRESULT QueryInterface(REFIID riid, void ** ppvObject) {
	if (riid is null || ppvObject is null)
		return COM.E_INVALIDARG;

	if (COM.IsEqualGUID(riid, &COM.IIDIUnknown)) {
		*ppvObject = cast(void*)(cast(IUnknown)iPropertyNotifySink);
		AddRef();
		return COM.S_OK;
	}
	if (COM.IsEqualGUID(riid, &COM.IIDIPropertyNotifySink)) {
		*ppvObject = cast(void*)(cast(IPropertyNotifySink)iPropertyNotifySink);
		AddRef();
		return COM.S_OK;
	}

	*ppvObject = null;
	return COM.E_NOINTERFACE;
}
ULONG AddRef() {
	refCount++;
	return refCount;
}
ULONG Release() {
	refCount--;
	if (refCount == 0) {
		disposeCOMInterfaces();
	}
	return refCount;
}

void addListener(int propertyID, OleListener listener) {
	if (listener is null) OLE.error (__FILE__, __LINE__, DWT.ERROR_NULL_ARGUMENT);
	if (eventTable is null) eventTable = new OleEventTable ();
	eventTable.hook(propertyID, listener);
}

void connect(IUnknown objIUnknown) {

	// Set up property change notification sink
	IConnectionPointContainer cpc;
	if (objIUnknown.QueryInterface(&COM.IIDIConnectionPointContainer, cast(void**)&cpc) == COM.S_OK) {
		IConnectionPoint cp;
		if (cpc.FindConnectionPoint(&COM.IIDIPropertyNotifySink, &cp) == COM.S_OK) {
			uint[] cookie = new uint[1];
			if (cp.Advise(cast(IPropertyNotifySink)iPropertyNotifySink, cookie.ptr) == COM.S_OK) {
				propertyCookie = cookie[0];
			}
			cp.Release();
		}
		cpc.Release();
	}
}
protected void createCOMInterfaces() {
	// register each of the interfaces that this object implements
	iPropertyNotifySink = new _IPropertyNotifySinkImpl(this);
}
void disconnect(IUnknown objIUnknown) {

	// disconnect property notification sink
	if (propertyCookie != 0 && objIUnknown !is null) {
		IConnectionPointContainer cpc;
		if (objIUnknown.QueryInterface(&COM.IIDIConnectionPointContainer, cast(void**)&cpc) == COM.S_OK) {
			IConnectionPoint cp;
			if (cpc.FindConnectionPoint(&COM.IIDIPropertyNotifySink, &cp) == COM.S_OK) {
				if (cp.Unadvise(propertyCookie) == COM.S_OK) {
					propertyCookie = 0;
				}
				cp.Release();
			}
			cpc.Release();
		}
	}
}
protected void disposeCOMInterfaces() {
	iPropertyNotifySink = null;
}
/**
* Notify listeners of an event.
* <p>
*	This method notifies all listeners that an event
* has occurred.
*
* @param eventType the desired DWT event
* @param event the event data
*
* @exception SWTError <ul>
*		<li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
*		<li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
* 		<li>ERROR_NULL_ARGUMENT when handler is null</li>
*	</ul>
*/
private void notifyListener (int eventType, OleEvent event) {
	if (event is null) OLE.error (__FILE__, __LINE__, DWT.ERROR_NULL_ARGUMENT);
	if (eventTable is null) return;
	event.type = eventType;
	event.widget = controlSite;
	eventTable.sendEvent (event);
}
package int OnChanged(int dispID) {

	if (eventTable is null || !eventTable.hooks(dispID)) return COM.S_OK;

	OleEvent event = new OleEvent();
	event.detail = OLE.PROPERTY_CHANGED;
	try {
		notifyListener(dispID, event);
	} catch (Exception e) {
	}

	return COM.S_OK;
}
package int OnRequestEdit(int dispID) {

	if (eventTable is null || !eventTable.hooks(dispID)) return COM.S_OK;

	OleEvent event = new OleEvent();
	event.doit = true;
	event.detail = OLE.PROPERTY_CHANGING;

	try {
		notifyListener(dispID,event);
	} catch (Exception e) {
	}

	if (event.doit) return COM.S_OK;

	return COM.S_FALSE;
}

void removeListener(int propertyID, OleListener listener) {
	if (listener is null) OLE.error (__FILE__, __LINE__, DWT.ERROR_NULL_ARGUMENT);
	if (eventTable is null) return;
	eventTable.unhook (propertyID, listener);
}

}
